package com.shelpe.services.tenant.item;

import java.io.InputStream;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommand;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandContext;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonCommandFactory;
import org.springframework.cloud.netflix.zuul.filters.route.apache.HttpClientRibbonCommandFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.MultiValueMap;

import com.netflix.client.ClientException;
import com.netflix.hystrix.exception.HystrixRuntimeException;
import com.netflix.zuul.exception.ZuulException;
import com.shelpe.services.tenant.mongomodel.SimbadTask;

public class TaskRequest {
	
	private static final Logger logger = LoggerFactory.getLogger(TaskRequest.class);
	
	private ProxyRequestHelper helper = new ProxyRequestHelper();
	
	private RibbonCommandFactory<?> ribbonCommandFactory = new HttpClientRibbonCommandFactory(new SpringClientFactory());
	
	
	public RibbonCommandContext buildCommandContext(SimbadTask taskParam) {
		
		MultiValueMap<String, String> headers = taskParam.getHeaders();
		MultiValueMap<String, String> params = taskParam.getParams();
		String verb = taskParam.getVerb();
		InputStream requestEntity = null;

		String serviceId = taskParam.getServiceId();
		Boolean retryable = true;

		String uri = taskParam.getTaskId();

		// remove double slashes
		uri = uri.replace("//", "/");

		logger.info("buildCommandContext uri {}", uri);
		
		return new RibbonCommandContext(serviceId, verb, uri, retryable, headers, params,
				requestEntity);
	}

	public ClientHttpResponse forward(RibbonCommandContext context) throws Exception {
		
		Map<String, Object> info = helper.debug(context.getVerb(), context.getUri(),
				context.getHeaders(), context.getParams(), context.getRequestEntity());

		RibbonCommand command = ribbonCommandFactory.create(context);
		
		logger.info("TaskRequest forward1 uri {}", context.getVerb());
		
		try {
			logger.info("TaskRequest forward2 uri {}", context.getVerb());
			ClientHttpResponse response = command.execute();
			logger.info("TaskRequest forward3 uri {}", context.getVerb());
			helper.appendDebug(info, response.getStatusCode().value(),
					response.getHeaders());
			return response;
		}
		catch (HystrixRuntimeException ex) {
			logger.info("TaskRequest forward4 uri {}, ex {}", context.getVerb(), ex);
			//return handleException(info, ex);
			return null;
		}

	}

	protected ClientHttpResponse handleException(Map<String, Object> info,
			HystrixRuntimeException ex) throws ZuulException {
		int statusCode = HttpStatus.INTERNAL_SERVER_ERROR.value();
		Throwable cause = ex;
		String message = ex.getFailureType().toString();

		ClientException clientException = findClientException(ex);
		if (clientException == null) {
			clientException = findClientException(ex.getFallbackException());
		}

		if (clientException != null) {
			if (clientException
					.getErrorType() == ClientException.ErrorType.SERVER_THROTTLED) {
				statusCode = HttpStatus.SERVICE_UNAVAILABLE.value();
			}
			cause = clientException;
			message = clientException.getErrorType().toString();
		}
		info.put("status", String.valueOf(statusCode));
		throw new ZuulException(cause, "Forwarding error", statusCode, message);
	}

	protected ClientException findClientException(Throwable t) {
		if (t == null) {
			return null;
		}
		if (t instanceof ClientException) {
			return (ClientException) t;
		}
		return findClientException(t.getCause());
	}

}
